-- ========================================================
-- @File	: timer.lua
-- @Brief	: 定时器组件
-- @Author	: Leo Zhao
-- @Date	: 2017-11-06
-- ========================================================
Timer = Timer or {
	tbTimer = {},
	nTimer	= 0,
	nNext	= -1,
}

-- 注册Timer
function Timer.Add(nDelay, f, ...)
	local tbEvent = { fOpt = f, tbParam = {...} };

	if nDelay <= 0 then
		nDelay = Call(tbEvent.fOpt, tbEvent.tbParam);
		if type(nDelay) ~= 'number' or nDelay <= 0 then return end;
	end

	tbEvent.nDelay = nDelay;
	tbEvent.nNext = Misc.nTick + nDelay;

	local nId = Timer.nTimer;
	Timer.tbTimer[nId] = tbEvent;
	Timer.nTimer = nId + 1;
	
	if Timer.nNext < 0 or Timer.nNext > tbEvent.nNext then Timer.nNext = tbEvent.nNext end;
	return nId;
end

-- 取消一个Timer
function Timer.Cancel(nId)
	local tbEvent = Timer.tbTimer[nId];
	if tbEvent then tbEvent.bCancel = true end;
end

-- 判断一个Timer是否被Cancel了
function Timer.IsValid(nId)
	return (Timer.tbTimer[nId] and not Timer.tbTimer[nId].bCancel);
end

-- 取得一个Timer下次执行还有多久（毫秒）
function Timer.GetLeftTime(nId)
	local tbEvent = Timer.tbTimer[nId];
	if not tbEvent or tbEvent.bCancel then return -1 end;
	return tbEvent.nNext - Misc.nTick;
end

---------------- 不可使用以下接口 --------------------------

-- 触发Timer
function Timer.Trigger()
	local nCur	= Misc.nTick;
	local tbDel	= {};
	local nNext	= -1;

	if Timer.nNext == -1 or nCur < Timer.nNext then return end;

	for nId, tbEvent in pairs(Timer.tbTimer) do
		if tbEvent.bCancel then
			table.insert(tbDel, nId);
		elseif tbEvent.nNext <= nCur then
			xpcall(function()
				local nDelay = Call(tbEvent.fOpt, tbEvent.tbParam);
				if not nDelay then
					tbEvent.nNext = tbEvent.nDelay + nCur;
					if nNext == -1 or nNext > tbEvent.nNext then nNext = tbEvent.nNext end;
				elseif nDelay <= 0 then
					table.insert(tbDel, nId);
				else
					tbEvent.nDelay = nDelay;
					tbEvent.nNext = nCur + nDelay;
					if nNext == -1 or nNext > tbEvent.nNext then nNext = tbEvent.nNext end;
				end
			end, function(err)
				table.insert(tbDel, nId);
				print_err(err);
			end);
		else
			if nNext == -1 or nNext > tbEvent.nNext then nNext = tbEvent.nNext end;
		end
	end

	for _, nId in ipairs(tbDel) do
		Timer.tbTimer[nId] = nil;
	end

	Timer.nNext = nNext;
end
